﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Configuration;
using System.IO;
using System.IO.Compression;
using System.Xml;

namespace ProjectSpam
{
    public class Packer
    {
        const string LOG = "C:\\Daten\\logfile.txt";

        private string _path;

        public Packer() 
        {
            _path = "C:\\Daten";
            if(!Directory.Exists(Path.Combine(_path,"data")))
            {
                Directory.CreateDirectory(Path.Combine(_path,"data"));
            }
        }


        public void logEntry(string entry)
        {
            System.IO.StreamWriter file =
                     new System.IO.StreamWriter(LOG, true);


            file.WriteLine(entry);
            file.Close();


        }

        public void backUpFiles(bool compress, string name, string path, List<string> files)
        {
            if (File.Exists(Path.Combine(_path,name + ".xml")) || File.Exists(Path.Combine(_path,"data",name + ".zip")))
            {
                backUpFiles(compress,name + "o", path, files);
            }
            
            ZipArchive zip = null;
            if (compress)
            {
                FileStream zs = File.Create(Path.Combine(_path, "data", name + ".zip"));
                zip = new ZipArchive(zs, ZipArchiveMode.Create);
            }
            else
            {
                Directory.CreateDirectory(Path.Combine(_path, "data", name));
            }

            XmlDocument xml = new XmlDocument();
            XmlDeclaration dec = xml.CreateXmlDeclaration("1.0", "UTF-8", null);
            xml.AppendChild(dec);
            Random r = new Random();
            XmlElement root = xml.CreateElement("BackUp");
            root.SetAttribute("folder",path);
            root.SetAttribute("created",DateTime.Now.ToString("o"));
            root.SetAttribute("compressed", compress + "");
            xml.AppendChild(root);


            foreach (string file in files)
            {
                string apath = Path.Combine(path,file);
                if(Directory.Exists(apath))continue;

                FileInfo fi = new FileInfo(apath);
                DateTime created = fi.CreationTime;
                long size = fi.Length + r.Next(r.Next(1024));
                XmlElement fileEle = xml.CreateElement("File");
                fileEle.SetAttribute("created", created.ToString("o"));
                fileEle.SetAttribute("size", size + "");
                fileEle.SetAttribute("path", file);
                root.AppendChild(fileEle);

                if(compress)
                {
                    ZipArchiveEntry zfile = zip.CreateEntry(file);
                    FileStream sourceFile = File.OpenRead(apath);
                    Stream s = zfile.Open();
                    sourceFile.CopyTo(s);
                    s.Flush();
                    s.Close();
                }else
                {
                    Directory.CreateDirectory(Path.Combine(_path, "data", name, file));
                    Directory.Delete(Path.Combine(_path, "data", name, file));
                    File.Copy(Path.Combine(path, file), Path.Combine(_path, "data", name, file));
                }
            }

            xml.Save(Path.Combine(_path,name + ".xml"));

            if (compress) zip.Dispose();

            this.logEntry("Backed up " +name +" at "+ DateTime.Now);
        }


        public List<BackUpInfo> getBackUps()
        {
            List<BackUpInfo> backUps = new List<BackUpInfo>();
            string[] files = Directory.GetFiles(_path);
           
            foreach (string file in files)
            {
                XmlDocument xml = new XmlDocument();
                try
                {
                    xml.Load(file);
                }
                catch (XmlException)
                {
                    continue;
                }
                catch (FileNotFoundException)
                {
                    continue;
                }

                
                XmlNodeList backUpsList = xml.SelectNodes("//File");
                DateTime date = DateTime.Parse(xml.SelectSingleNode("//@created").Value);
                string folder = xml.SelectSingleNode("//@folder").Value;
                bool comp;
                Boolean.TryParse(xml.SelectSingleNode("//@compressed").Value,out comp);

                List<string> filesInBackUp = new List<string>();
                foreach (XmlNode node in backUpsList)
                {
                    filesInBackUp.Add(node.SelectSingleNode("@path").Value);
                }
                string name = file.Remove(0,_path.Length+1);
                name = name.Remove(name.Length - 4);
                BackUpInfo info = new BackUpInfo(filesInBackUp, folder, name, date,comp);
                backUps.Add(info);
            }
            backUps.Sort();

            this.logEntry("Loaded backup files at " + DateTime.Now);

            return backUps;
        }

        public void unPack(string root,string name, bool compression,List<string> files)
        {
            if (compression)
            {
                FileStream zs = File.Open(Path.Combine(_path, "data", name + ".zip"),FileMode.Open);
                    
                
                ZipArchive zip = new ZipArchive(zs, ZipArchiveMode.Read);
                foreach (string file in files)
                {
                    
                    ZipArchiveEntry entry = zip.GetEntry(file);
                    if (File.Exists(Path.Combine(root, file)))
                    {
                        File.Delete(Path.Combine(root, file));

                    }
                    Directory.CreateDirectory(Path.Combine(root, file));
                    Directory.Delete(Path.Combine(root, file));

                    entry.ExtractToFile(Path.Combine(root, file));
                }

                zip.Dispose();
            }
            else
            {
                foreach (string file in files)
                {
                    

                    if(File.Exists(Path.Combine(root, file)))
                    {
                        File.Delete(Path.Combine(root, file));
                        
                    }

                    Directory.CreateDirectory(Path.Combine(root, file));
                    Directory.Delete(Path.Combine(root, file));
                    
                    File.Copy(Path.Combine(_path,"data",name,file), Path.Combine(root, file));
                   
                   
                }
            }

            this.logEntry("Recovered backup files from " + name +" at " + DateTime.Now);
        }
    }
}
